package fr.starn.domoticz_widgets;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import android.content.Context;
import android.graphics.Color;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.auth.AuthScope;
import ch.boye.httpclientandroidlib.auth.UsernamePasswordCredentials;
import ch.boye.httpclientandroidlib.client.HttpClient;
import ch.boye.httpclientandroidlib.client.methods.HttpGet;
import ch.boye.httpclientandroidlib.client.params.ClientPNames;
import ch.boye.httpclientandroidlib.conn.ClientConnectionManager;
import ch.boye.httpclientandroidlib.conn.scheme.Scheme;
import ch.boye.httpclientandroidlib.conn.scheme.SchemeRegistry;
import ch.boye.httpclientandroidlib.conn.ssl.SSLSocketFactory;
import ch.boye.httpclientandroidlib.impl.auth.BasicScheme;
import ch.boye.httpclientandroidlib.impl.client.AbstractHttpClient;
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
import ch.boye.httpclientandroidlib.params.BasicHttpParams;
import ch.boye.httpclientandroidlib.params.HttpConnectionParams;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
import ch.boye.httpclientandroidlib.util.EntityUtils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import fr.starn.domoticz_widgets.JSonObject.DeviceProps;
import fr.starn.domoticz_widgets.JSonObject.DevicesProps;

public class RestRequestHandler implements Runnable{
	
	public static String LIST="LIST";
	public static String COMMAND="COMMAND";
	
	private WidgetPropertiesBean connectionProp;
	private Context context;
	private IValueReceiver parent;
	private String command;
	private boolean useCache;
	
	private static Map<String,String> cache = new HashMap<String,String>();
	private static long cacheTime;
	private static final long cacheDuration = 1000*60*20;//20 minutes
	
	
	/**
	 * constructor to get values
	 */
	public RestRequestHandler(Context context, IValueReceiver parent, WidgetPropertiesBean connectionProp, String command){
		if (cache==null) cache=new HashMap<String,String>();
		this.context=context;
		this.parent=parent;
		this.command=command;
		this.connectionProp=connectionProp;
		this.useCache=true;
	}
	
	public RestRequestHandler(Context context, IValueReceiver parent, WidgetPropertiesBean connectionProp, String command,boolean useCache){
		if (cache==null) cache=new HashMap<String,String>();
		this.context=context;
		this.parent=parent;
		this.command=command;
		this.connectionProp=connectionProp;
		this.useCache=useCache;
	}

	
	public void run(){
    	if (connectionProp.getHost()==null || "".equals(connectionProp.getHost())){
    		parent.manageError(context,connectionProp, "Widget not configured");
    		return;
    	}
		if (LIST.equals(command)) list();
		if (COMMAND.equals(command)) command();
	}
	
	public void command(){
		try {
			//cache.clear();
			//refresh light status
	    	String protocol = connectionProp.isSecured()?"https":"http";
	        String request = protocol+"://"+connectionProp.getHost()+":"+connectionProp.getPort()+"/json.htm?type=devices&filter=all&used=true&order=Name&plan=0";
	        String content = null;
	        if (cache.get(request)!=null){
	        	content = cache.get(request);
	        } else {
	        	content = launchHttpRequest(request);
	        }
	        DevicesProps devicesResult = new DevicesProps();
	        DevicesProps jsonProps =DevicesProps.deserialize(content);
	        List<DeviceProps> devices = jsonProps.getResult();
	        String newStatus = "Off";
	        String deviceId = "-1";
	        for (DeviceProps device: devices){
	        	if ( device.getName().equals(connectionProp.getDevice())){
	        		if ("Off".equals(device.getStatus())) newStatus="On";
	        		deviceId=device.getIdx();
	        	}
	        }
			
	        request = protocol+"://"+connectionProp.getHost()+":"+connectionProp.getPort()+"/json.htm?type=command&param=switchlight&idx="+deviceId+"&switchcmd="+newStatus+"&level=0";
	        launchHttpRequest(request);
	        
	        //refresh
	        cache.clear();
	        //list();
		} catch (Exception e){
			e.printStackTrace();
		}
		list();
	}
	
	
	
	public void list(){
	    try {
	    	String protocol = connectionProp.isSecured()?"https":"http";
	        String request = protocol+"://"+connectionProp.getHost()+":"+connectionProp.getPort()+"/json.htm?type=devices&filter=all&used=true&order=Name&plan=0";
	        String content = launchHttpRequest(request);
	        
	        DevicesProps devicesResult = new DevicesProps();
	        devicesResult.setResult(new ArrayList<DeviceProps>());
	        
	        DevicesProps jsonProps =DevicesProps.deserialize(content);
	        for (DeviceProps jsonProp: jsonProps.getResult()){
	        	if ( jsonProp.getName().equals(connectionProp.getDevice())){
	        		
	        		devicesResult.getResult().add(jsonProp);
	        	} else if ( connectionProp.getDevice()==null && (jsonProp.isTemp() || jsonProp.isLight())){
	        		devicesResult.getResult().add(jsonProp);
	        	}
	        	
	        }
	        
	        parent.updateValue(context,connectionProp,devicesResult);
	        //return content;
	    } catch (Exception e) {
	        e.printStackTrace();
	        //return "Error";
	        parent.manageError(context, connectionProp,e.getMessage());
	    }
	}
		
	
	private String launchHttpRequest(String request) throws Exception{
		long currenttime=new Date().getTime();
		if (useCache && cache!=null && (currenttime-cacheTime)<cacheDuration && cache.get(request)!=null){
			System.out.println("request in cache: "+request);
			return cache.get(request);
		}
		
        final HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, 20000);//20 seconds
        HttpClient defaultHttpClient = new DefaultHttpClient(httpParams);
        
		AbstractHttpClient client = wrapClient(defaultHttpClient);
		client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
		
        AuthScope as = new AuthScope(connectionProp.getHost(), connectionProp.getPort());
        
        
        BasicHttpContext localContext = new BasicHttpContext();
        if (connectionProp.getLogin()!=null && connectionProp.getPassword()!=null && !"".equals(connectionProp.getLogin())){
            UsernamePasswordCredentials upc = new UsernamePasswordCredentials(
            		connectionProp.getLogin(), connectionProp.getPassword());
            ((AbstractHttpClient) client).getCredentialsProvider()
                    .setCredentials(as, upc);
            
            BasicScheme basicAuth = new BasicScheme();
            localContext.setAttribute("preemptive-auth", basicAuth);
        }
        
        
        String protocol = connectionProp.isSecured()?"https":"http";
        HttpHost targetHost = new HttpHost(connectionProp.getHost(),connectionProp.getPort(),protocol);
        System.out.println("exec req:"+request);
        HttpGet httpget = new HttpGet(request);
        httpget.setHeader("Content-Type", "application/xml");
        
        HttpResponse response = client.execute(targetHost, httpget,
                localContext);
        if (response.getStatusLine().getStatusCode()==401){
        	System.err.println("401 bad auth");
        	throw new Exception("401 bad auth");
        }
        if (response.getStatusLine().getStatusCode()==404){
        	System.err.println("404 not found");
        	throw new Exception("404 not found");
        }
        HttpEntity entity = response.getEntity();
        String content = EntityUtils.toString(entity);
        cache.put(request, content);
        cacheTime=currenttime;
        return content;
	}
	
//	private DeviceProps[] ListToArray(List<DeviceProps> list){
//		DeviceProps[] array = new DeviceProps[list.size()];
//		int i = 0;
//		for (DeviceProps p: list){
//			array[i]=p;
//			i++;
//		}
//		return array;
//	}
	
	
	private static AbstractHttpClient wrapClient(HttpClient base) {
		try {
			SSLContext ctx = SSLContext.getInstance("TLS");
			X509TrustManager tm = new X509AlwaysTrust();

			ctx.init(null, new TrustManager[] { tm }, null);
			SSLSocketFactory ssf = new SSLSocketFactory(
					ctx);
			ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			ClientConnectionManager ccm = base.getConnectionManager();
			SchemeRegistry sr = ccm.getSchemeRegistry();
			sr.register(new Scheme("https", ssf, 443));
			return new DefaultHttpClient(ccm, base.getParams());
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}








}
